package edu.eas.admin.service.impl;

import edu.eas.admin.mapper.MenuMapper;
import edu.eas.admin.mapper.RoleMapper;
import edu.eas.admin.mapper.RoleMenuMapper;
import edu.eas.admin.service.AdminService;
import edu.eas.admin.service.MenuService;
import edu.eas.common.constant.AuthConstant;
import edu.eas.common.constant.Constants;
import edu.eas.common.dto.MenuNode;
import edu.eas.common.dto.TreeSelect;
import edu.eas.common.pojo.Admin;
import edu.eas.common.pojo.Menu;
import edu.eas.common.pojo.Role;
import edu.eas.common.pojo.RoleMenu;
import edu.eas.common.service.RedisService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author cql
 */
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private AdminService adminService;

    @Autowired
    private RedisService redisService;

    @Value("${spring.application.name}")
    private String applicationName;

    @Override
    public Map<String, List<String>> initMenuRolesMap() {
        Map<String, List<String>> menuRoleMap = new TreeMap<>();
        // 1.获取所有菜单信息
        List<Menu> menuList = menuMapper.getMenuAll(null, Constants.STATUS_YES);
        // 2.获取所有角色信息
        List<Role> roleList = roleMapper.getRoleAll(null, Constants.STATUS_YES);
        // 3.获取角色-菜单关系
        List<RoleMenu> relationList = roleMenuMapper.getRoleMenuAll();
        // 4.组装
        for (Menu menu : menuList) {
            Set<Long> roleIds = relationList.stream().filter(item -> item.getMenuId().equals(menu.getMenuId())).map(RoleMenu::getRoleId).collect(Collectors.toSet());
            List<String> roleNames = roleList.stream().filter(item -> roleIds.contains(item.getRoleId())).map(item -> item.getRoleId() + "_" + item.getRoleKey()).collect(Collectors.toList());
            menuRoleMap.put("/" + applicationName + menu.getPath(), roleNames);
        }
        // 5.存入Redis
        redisService.hSetAll(AuthConstant.RESOURCE_ROLES_MAP_KEY, menuRoleMap);
        return menuRoleMap;
    }

    @Override
    public List<MenuNode> treeList(String menuName, Integer status) {
        // 1.先获取所有菜单(可用的与不可用的)
        List<Menu> menuList = menuMapper.getMenuAll(menuName, status);
        // 2.组装
        return build(menuList, menuName);
    }

    @Override
    public int deleteById(Long id) {
        // 1.先判断有没有子菜单
        List<Menu> children = menuMapper.getChildrenByParentId(id);
        if (children.size() > 0) {
            return 0;
        }
        // TODO 删除 角色-菜单关联
        return menuMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Menu getMenu(Long menuId) {
        return menuMapper.getByPrimaryKey(menuId);
    }

    @Override
    public int create(Menu menu) {
        // TODO 先判断存不存在相同的菜单
        Admin admin = adminService.getCurrentAdmin();
        Date now = new Date();
        // 1.创建时间
        menu.setCreateTime(now);
        // 2.创建人
        menu.setCreateBy(admin.getAdminId());
        // 3.更新时间
        menu.setUpdateTime(now);
        // 4.更新人
        menu.setUpdateBy(admin.getAdminId());

        return menuMapper.insert(menu);
    }

    @Override
    public int update(Long id, Menu menu) {
        Admin admin = adminService.getCurrentAdmin();
        // 1.设置ID
        menu.setMenuId(id);
        // 2.设置更新时间
        menu.setUpdateTime(new Date());
        // 3.设置更新者
        menu.setUpdateBy(admin.getAdminId());

        return menuMapper.update(menu);
    }

    @Override
    public List<MenuNode> treeselect(String menuName, int status) {
        Admin admin = adminService.getCurrentAdmin();
        if (admin.getAdminId().equals(1L)) {
            return this.treeList(menuName, status);
        } else {
            List<Menu> menuList = menuMapper.selectMenuListByAdminId(admin.getAdminId(), menuName, status);
            return build(menuList, menuName);
        }
    }

    @Override
    public List<MenuNode> selectMenuList() {
        return treeselect(null, -1);
    }

    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        return menuMapper.selectMenuListByRoleId(roleId);
    }

    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<MenuNode> menus) {
        return menus.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    @Override
    public List<MenuNode> selectMenuTreeAll() {
        List<Menu> menuList = menuMapper.selectMenuTreeAll();
        return build(menuList, null);
    }

    @Override
    public List<MenuNode> selectMenuTreeByAdminId(Long adminId) {
        List<Menu> menuList = menuMapper.selectMenuTreeByAdminId(adminId);
        return build(menuList, null);
    }


    private List<MenuNode> build(List<Menu> menuList, String menuName) {
        List<MenuNode> result = menuList.stream()
                .filter(menu -> menu.getParentId().equals(0L))
                .map(menu -> covertMenuNode(menu, menuList, menuName))
                .collect(Collectors.toList());
        // 3.兼容模糊查询
        if (menuList != null && menuName != null && !"".equals(menuName)) {
            List<MenuNode> temp = menuList.stream()
                    .filter(menu -> !menu.getParentId().equals(0L))
                    .map(menu -> covertMenuNode(menu, menuList, menuName))
                    .collect(Collectors.toList());
            result.addAll(temp);
        }
        return result;
    }

    /**
     * 将Menu转化为MenuNode并设置children属性
     */
    private MenuNode covertMenuNode(Menu menu, List<Menu> menuList, String menuName) {
        MenuNode node = new MenuNode();
        BeanUtils.copyProperties(menu, node);
        List<MenuNode> children = menuList.stream()
                .filter(subMenu -> subMenu.getParentId().equals(menu.getMenuId()))
                .map(subMenu -> covertMenuNode(subMenu, menuList, menuName)).collect(Collectors.toList());
        node.setChildren(children);
        return node;
    }

}
